<script setup lang="ts">
  import { computed, CSSProperties, PropType, ref, watch } from 'vue'
  import { ElImage } from 'element-plus'

  const props = defineProps({
    src: {
      type: String,
      default: () => '',
    },
    fit: {
      type: String as PropType<'' | 'fill' | 'contain' | 'cover' | 'none' | 'scale-down'>,
      default: () => 'contain',
    },
    alt: {
      type: String,
      default: () => '',
    },
    previewSrcList: {
      type: Array as PropType<Array<string>>,
      default: () => [],
    },
    initialIndex: {
      type: Number,
      default: () => 0,
    },
    width: {
      type: Number,
      default: () => 100,
    },
    height: {
      type: Number,
      default: () => 100,
    },
    showDelBtn: {
      type: Boolean,
      default: () => true,
    },
    showPreviewBtn: {
      type: Boolean,
      default: () => true,
    },
    showMask: {
      type: Boolean,
      default: () => true,
    },
    padding: {
      type: Number,
      default: () => 8,
    },
    isShowImgPreview: {
      type: Boolean,
      default: () => true,
    },
    maskBtnGap: {
      type: Number,
      default: () => 12,
    },
    maskHeight: {
      type: Number,
      default: () => 100,
    },
    maskHeightUnit: {
      type: String as PropType<'px' | '%'>,
      default: () => '%',
    },
    borderColor: {
      type: String,
      default: () => '#ebeef5',
    },
  })

  const emits = defineEmits<{
    (e: 'del'): void
    (e: 'preview'): void
    (e: 'maskClick'): void
    (e: 'imgClick'): void
  }>()

  // 是否显示预览图
  const isPreview = ref(false)

  // 是否显示蒙版
  const isShowMask = ref(true)

  // 图片预览链接列表
  const picturePreviewList = computed<Array<string>>(() => {
    if (props.previewSrcList.length === 0) {
      return [props.src]
    }

    return props.previewSrcList
  })

  // 初始预览图像的索引
  const initialIndex = computed(() => {
    if (props.initialIndex < 0) {
      return 0
    }

    if (props.initialIndex > picturePreviewList.value.length - 1) {
      return picturePreviewList.value.length - 1
    }

    return props.initialIndex
  })

  // 蒙版内容div
  const maskContentDiv = ref<HTMLDivElement | null>(null)

  // 图片组件样式
  const hImageStyle = computed<CSSProperties>(() => {
    return {
      width: `${Number(props.width)}px`,
      height: `${Number(props.height)}px`,
      padding: `${Number(props.padding)}px`,
      borderColor: props.borderColor,
    }
  })

  /**
   * 预览事件
   */
  const onPreview = () => {
    isPreview.value = props.isShowImgPreview && true
    emits('preview')
  }

  /**
   * 蒙版点击事件
   * 如果蒙版内容div有的话就证明默认插槽没有被占用，使用这种方式来判断默认插槽是否被占用是因为：
   * useSlots()得到的默认插槽始终都是true，就是不管有没有使用默认插槽，得到的结果都是true
   */
  const onMaskClick = () => {
    if (maskContentDiv.value) {
      isPreview.value = props.isShowImgPreview && true
    }
    emits('maskClick')
  }

  watch(
    props,
    (value) => {
      isShowMask.value = value.showMask
    },
    { immediate: true, deep: true },
  )
</script>

<template>
  <div class="h_image" :style="hImageStyle" @click="emits('imgClick')">
    <el-image :src="props.src" :alt="props.alt" :fit="props.fit" loading="lazy" lazy />

    <div v-if="$slots.desc" class="desc">
      <slot name="desc"></slot>
    </div>

    <div
      v-if="isShowMask"
      class="operate_mask"
      :style="{
        gap: `${props.maskBtnGap}px`,
        height: `${props.maskHeight}${props.maskHeightUnit}`,
      }"
      @click.stop="onMaskClick"
    >
      <slot>
        <div
          ref="maskContentDiv"
          class="mask-content"
          :style="{
            gap: `${props.maskBtnGap}px`,
            height: `${props.maskHeight}${props.maskHeightUnit}`,
          }"
        >
          <i v-if="props.showPreviewBtn" class="iconfont icon-preview" @click.stop="onPreview"></i>
          <i v-if="props.showDelBtn" class="iconfont icon-del" @click.stop="emits('del')"></i>
        </div>
      </slot>
    </div>
    <div class="content_mask">
      <slot name="contentMask"></slot>
    </div>

    <el-image-viewer
      v-if="isPreview"
      :url-list="picturePreviewList"
      :initial-index="initialIndex"
      infinite
      teleported
      @close="isPreview = false"
    />
  </div>
</template>

<style scoped lang="scss">
  .h_image {
    position: relative;
    border-radius: 2px;
    box-sizing: border-box;
    padding: 8px;
    border-width: 1px;
    border-style: solid;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    cursor: pointer;

    :deep(.el-image) {
      width: 100%;
      height: 100%;
      display: flex;
      align-items: center;
    }

    .desc {
      line-height: 14px;
      height: 14px;
      color: #606266;
    }

    &:hover {
      .operate_mask {
        opacity: 1;
      }
    }

    .operate_mask {
      position: absolute;
      bottom: 0;
      left: 0;
      width: 100%;
      background-color: rgba(#000, 0.4);
      display: flex;
      justify-content: center;
      align-items: center;
      opacity: 0;
      transition: opacity 0.4s;
      z-index: 999;

      .mask-content {
        width: 100%;
        height: 100%;
        display: flex;
        justify-content: center;
        align-items: center;

        .iconfont {
          color: #fff;
          font-size: 16px;
          cursor: pointer;
        }
      }
    }

    .content_mask {
      position: absolute;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      z-index: 998;
    }
  }
</style>
